﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace DemoDepthFrame
{
    using Microsoft.Research.Kinect;
    using Microsoft.Research.Kinect.Nui;

    /// <summary>
    /// MainWindow.xaml の相互作用ロジック
    /// </summary>
    public partial class MainWindow : Window
    {
        private Runtime runtime;
        private bool usePlayerIndex = true;
        public MainWindow()
        {
            InitializeComponent();

        }

        byte[] depthFrame32 = new byte[320 * 240 * 4];

        void runtime_DepthFrameReady1(object sender, ImageFrameReadyEventArgs e)
        {
            PlanarImage image = e.ImageFrame.Image;
            byte[] depthImage = ConvertDepthFrame(image.Bits);
            depthFrameImage.Source = BitmapSource.Create(
                image.Width, image.Height, 96, 96,
                PixelFormats.Bgr32, null,
                depthImage, image.Width * 4);
        }
        void runtime_DepthFrameReady2(object sender, ImageFrameReadyEventArgs e)
        {
            PlanarImage image = e.ImageFrame.Image;
            byte[] depthImage = ConvertDepthFrame2(image.Bits);
            depthFrameImage.Source = BitmapSource.Create(
                image.Width, image.Height, 96, 96,
                PixelFormats.Bgr32, null,
                depthImage, image.Width * 4);
        }
        void runtime_DepthFrameReady3(object sender, ImageFrameReadyEventArgs e)
        {
            PlanarImage image = e.ImageFrame.Image;
            byte[] depthImage = ConvertDepthFrame3(image.Bits);
            depthFrameImage.Source = BitmapSource.Create(
                image.Width, image.Height, 96, 96,
                PixelFormats.Bgr32, null,
                depthImage, image.Width * 4);
        }

        const int RED_IDX = 0;
        const int GREEN_IDX = 1;
        const int BLUE_IDX = 2;

        // PlayerIndex specific
        byte[] ConvertDepthFrame3(byte[] depthFrame16)
        {
            for (int i16 = 0, i32 = 0;
                i16 < depthFrame16.Length && i32 < depthFrame32.Length;
                i16 += 2, i32 += 4)
            {
                int player = depthFrame16[i16] & 0x07;
                int realDepth  = (depthFrame16[i16 + 1] << 5) | (depthFrame16[i16] >> 3);
                // transform 13-bit depth information into an 8-bit intensity appropriate
                // for display (we disregard information in most significant bit)
                byte intensity = (byte)(255 - (255 * realDepth / 0x0fff));
//                byte intensity = (byte)(0xff-(realDepth >> 5));

                depthFrame32[i32 + RED_IDX] = 0;
                depthFrame32[i32 + GREEN_IDX] = 0;
                depthFrame32[i32 + BLUE_IDX] = 0;

                // choose different display colors based on player
                switch (player)
                {
                    case 0:
                        break;
                    case 1:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        break;
                    case 2:
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 3:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 4:
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        break;
                    case 5:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        break;
                    case 6:
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 7:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                }
            }
            return depthFrame32;
        }
        byte[] ConvertDepthFrame(byte[] depthFrame16)
        {
            for (int i16 = 0, i32 = 0;
                i16 < depthFrame16.Length && i32 < depthFrame32.Length;
                i16 += 2, i32 += 4)
            {
                int player = depthFrame16[i16] & 0x07;
                int realDepth = 0;
                if (usePlayerIndex)
                {
                    realDepth = (depthFrame16[i16 + 1] << 5) | (depthFrame16[i16] >> 3);
                }
                else
                {
                    realDepth = (depthFrame16[i16 + 1] << 8 | depthFrame16[i16]);
                }
                // transform 13-bit depth information into an 8-bit intensity appropriate
                // for display (we disregard information in most significant bit)
                byte intensity = (byte)(255 - (255 * realDepth / 0x0fff));

                depthFrame32[i32 + RED_IDX] = 0;
                depthFrame32[i32 + GREEN_IDX] = 0;
                depthFrame32[i32 + BLUE_IDX] = 0;

                // choose different display colors based on player
                switch (player)
                {
                    case 0:
                        depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2);
                        depthFrame32[i32 + GREEN_IDX] = (byte)(intensity / 2);
                        depthFrame32[i32 + BLUE_IDX] = (byte)(intensity / 2);
                        break;
                    case 1:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        break;
                    case 2:
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 3:
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        break;
                    case 4:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 5:
                        depthFrame32[i32 + RED_IDX] = intensity;
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        break;
                    case 6:
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        depthFrame32[i32 + BLUE_IDX] = intensity;
                        break;
                    case 7:
                        depthFrame32[i32 + RED_IDX] = (byte)(intensity / 2);
                        depthFrame32[i32 + GREEN_IDX] = intensity;
                        break;
                }
            }
            return depthFrame32;
        }

        private int realDepthMin=0x7fffffff;
        private int realDepthMax = 0x0;

        byte[] ConvertDepthFrame2(byte[] depthFrame16)
        {
            for (int i16 = 0, i32 = 0;
                i16 < depthFrame16.Length && i32 < depthFrame32.Length;
                i16 += 2, i32 += 4)
            {
    //            int player = depthFrame16[i16] & 0x07;
                int realDepth = (depthFrame16[i16 + 1] << 8 | depthFrame16[i16]);
                // transform 13-bit depth information into an 8-bit intensity appropriate
                // for display (we disregard information in most significant bit)

                if (realDepth < realDepthMin)
                {
                    realDepthMin = realDepth;
                }
                if (realDepthMax < realDepth)
                {
                    realDepthMax = realDepth;
                    if (realDepth == 0xffff)
                    {
                        realDepthMax = realDepth;
                    }
                }

                depthFrame32[i32 + RED_IDX] = 0;
                depthFrame32[i32 + GREEN_IDX] = 0;
                depthFrame32[i32 + BLUE_IDX] = 0;

                int red = 0;
                int blue = 0;
                int green = 0;
                blue = realDepth & 0x3f;
                blue <<= 2;
                if (realDepth >= 0x40)
                {
                    green = realDepth & 0xfc0;
                    green >>= 4;
                }
                if (realDepth >= 0x1000)
                {
                    red = (realDepth >> 12);
                    red <<= 2;
                }

                depthFrame32[i32 + RED_IDX] = (byte)red;
                depthFrame32[i32 + GREEN_IDX] = (byte)green;
                depthFrame32[i32 + BLUE_IDX] = (byte)blue;

            }
            return depthFrame32;
        }

        private void cmbBoxMode_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (runtime != null)
            {
                runtime.Uninitialize();
            }
            int depthMode = 0;
            string selectedMode = ((ComboBoxItem)cmbBoxMode.SelectedItem).Content.ToString();
            if (selectedMode.CompareTo("SDK Sample") == 0)
            {
                depthMode = 1;
            }
            else if (selectedMode.CompareTo("Depth Only") == 0)
            {
                depthMode = 2;
            }
            else if (selectedMode.CompareTo("Depth with PlayerIndex") == 0)
            {
                depthMode = 3;
            }
            if (depthMode > 0)
            {
                runtime = new Runtime();
                if (depthMode == 1 || depthMode == 3)
                {
                    runtime.Initialize(RuntimeOptions.UseDepth | RuntimeOptions.UseDepthAndPlayerIndex | RuntimeOptions.UseSkeletalTracking);
                    runtime.DepthStream.Open(
                        ImageStreamType.Depth, 2,
                        ImageResolution.Resolution320x240,
                        ImageType.DepthAndPlayerIndex);
                }
                else
                {
                    runtime.Initialize(RuntimeOptions.UseDepth);
                    runtime.DepthStream.Open(
                      ImageStreamType.Depth, 2,
                    ImageResolution.Resolution320x240,
                  ImageType.Depth);
                }

                switch (depthMode)
                {
                    case 1: // SDK Sample
                        runtime.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(runtime_DepthFrameReady1);
                        break;
                    case 2: // Depth Only
                        runtime.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(runtime_DepthFrameReady2);
                        break;
                    case 3: // Depth Only
                        runtime.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(runtime_DepthFrameReady3);
                        break;
                }
            }
        }
    }
}
